package com.zt.proxy.component;

import org.apache.commons.lang3.StringUtils;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.zt.proxy.model.PomModel;

import lombok.extern.slf4j.Slf4j;

@Configuration
@EnableAutoConfiguration
@ComponentScan
@Slf4j
public class DependencyFactory {

    @Value("${proxy.dependency.repository}")
    private String repository;

    @Value("${proxy.dependency.username}")
    private String username = null;
    
    @Value("${proxy.dependency.password}")
    private String password = null;
    
    @Value("${proxy.dependency.lib}")
    private String libPath = null;
    /**
     * 生成 RepositorySystem
     *
     * @return RepositorySystem
     */
    public RepositorySystem newRepositorySystem() {
        DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
        locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
        locator.addService(TransporterFactory.class, FileTransporterFactory.class);
        locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
        log.info("create RepositorySystem");
        return locator.getService(RepositorySystem.class);
    }
 
    /**
     * 生成 RepositorySystemSession
     *
     * @param system RepositorySystem
     * @return RepositorySystemSession
     */
    public RepositorySystemSession newSession(RepositorySystem system) {
        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
        LocalRepository localRepo = newLocalRepository();
        session.setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true);
        session.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
        session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
        log.info("create RepositorySystemSession");
        return session;
    }
 
    /**
     * 生成 RemoteRepository
     *
     * @param params
     * @return
     */
    public RemoteRepository newRemoteRepository() {
        RemoteRepository central;
        log.info("create personal RemoteRepository");
        if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
            central = new RemoteRepository.Builder("central", "default", repository).build();
        } else {
            Authentication authentication = new AuthenticationBuilder().addUsername(username).addPassword(password).build();
            central = new RemoteRepository.Builder("central", "default",
                                                   repository).setAuthentication(authentication).build();
        }

        return central;

    }
 
    /**
     * 生成 LocalRepository
     *
     * @param target
     * @return
     */
    public LocalRepository newLocalRepository(String target) {
        if (StringUtils.isBlank(target)) {
            log.info("create Default LocalRepository");
            return new LocalRepository(libPath);
 
        } else {
            log.info("create personal LocalRepository");
            return new LocalRepository(target);
        }
    }
    
    /**
     * 生成 LocalRepository
     *
     * @param target
     * @return
     */
    public LocalRepository newLocalRepository() {
        return newLocalRepository("");
    }
 
    public DefaultArtifact newDefaultArtifact(String artifactId, String groupId, String version) {
        log.info("create DefaultArtifact");
        String artifactStr = groupId + ":" + artifactId + ":" + version;
        return new DefaultArtifact(artifactStr);
    }
    
    /**
     * 下载jar包
     * @throws Exception 
     */
    public void downLoadMavenJar(PomModel pomModel) throws Exception{
        RepositorySystem repoSystem = newRepositorySystem();
        RepositorySystemSession session = newSession(repoSystem);
        RemoteRepository central = newRemoteRepository();
 
        //下载该jar包及其所有依赖jar包
        DefaultArtifact defaultArtifact = newDefaultArtifact(pomModel.getArtifactId(), pomModel.getGroupId(), pomModel.getVersion());
        Dependency dependency = new Dependency(defaultArtifact, null);
 
        CollectRequest collectRequest = new CollectRequest();
        collectRequest.setRoot(dependency);
        collectRequest.addRepository(central);
        DependencyNode node = repoSystem.collectDependencies(session, collectRequest).getRoot();
 
        DependencyRequest dependencyRequest = new DependencyRequest();
        dependencyRequest.setRoot(node);
 
        repoSystem.resolveDependencies(session, dependencyRequest);
 
        PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
        node.accept(nlg);
        log.info("download end");
    }

}
